package com.zjmzxfzhl.modules.purchase.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zjmzxfzhl.common.base.BaseServiceImpl;
import com.zjmzxfzhl.common.exception.AppException;
import com.zjmzxfzhl.common.exception.BaseException;
import com.zjmzxfzhl.common.util.Amount2RMBUtil;
import com.zjmzxfzhl.common.util.PathUtil;
import com.zjmzxfzhl.common.util.bs.PurchaseUtils;
import com.zjmzxfzhl.modules.purchase.controller.dto.PurchaseContractDto;
import com.zjmzxfzhl.modules.purchase.controller.dto.PurchaseContractQueryDto;
import com.zjmzxfzhl.modules.purchase.controller.dto.PurchaseOrderDetailDto;
import com.zjmzxfzhl.modules.purchase.controller.dto.PurchasePaymentDto;
import com.zjmzxfzhl.modules.purchase.controller.vo.PurchaseContractDetailVo;
import com.zjmzxfzhl.modules.purchase.controller.vo.PurchaseContractVo;
import com.zjmzxfzhl.modules.purchase.controller.vo.PurchaseIndentSimpleVo;
import com.zjmzxfzhl.modules.purchase.controller.vo.PurchaseIndentVo;
import com.zjmzxfzhl.modules.purchase.controller.vo.PurchaseOrderDetailVo;
import com.zjmzxfzhl.modules.purchase.entity.PurchaseContract;
import com.zjmzxfzhl.modules.purchase.entity.PurchaseIndent;
import com.zjmzxfzhl.modules.purchase.entity.PurchaseOrder;
import com.zjmzxfzhl.modules.purchase.entity.PurchaseOrderDetail;
import com.zjmzxfzhl.modules.purchase.entity.PurchasePayment;
import com.zjmzxfzhl.modules.purchase.entity.PurchaseSupplier;
import com.zjmzxfzhl.modules.purchase.mapper.PurchaseContractMapper;
import com.zjmzxfzhl.modules.purchase.mapper.PurchaseOrderMapper;
import com.zjmzxfzhl.modules.purchase.service.PurchaseContractService;
import com.zjmzxfzhl.modules.purchase.service.PurchaseIndentService;
import com.zjmzxfzhl.modules.purchase.service.PurchaseOrderDetailService;
import com.zjmzxfzhl.modules.purchase.service.PurchasePaymentService;
import com.zjmzxfzhl.modules.purchase.service.PurchaseSupplierService;
import com.zjmzxfzhl.modules.purchase.service.bo.PaymentApprovalInfo;
import com.zjmzxfzhl.modules.purchase.service.bo.PurchaseMaterialBo;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Service
 *
 * @author yangjf
 */
@Service
public class PurchaseContractServiceImpl extends BaseServiceImpl<PurchaseContractMapper, PurchaseContract> implements PurchaseContractService {

    public static int PROPORTION_100 = 100;

    @Autowired
    private PurchaseIndentService indentService;

    @Autowired
    private PurchaseOrderDetailService detailService;

    @Autowired
    private PurchaseOrderMapper orderMapper;

    @Autowired
    private PurchaseSupplierService supplierService;

    @Autowired
    private PurchasePaymentService paymentService;

    @Override
    public IPage<PurchaseContractVo> list(IPage<PurchaseContractVo> page, PurchaseContractQueryDto purchaseContract) {
        List<PurchaseContractVo> contractVos = baseMapper.list(page, purchaseContract);

        for (PurchaseContractVo contractVo : contractVos) {
            //计算金额
            //查找details
            PurchaseOrderDetailDto detailDto = new PurchaseOrderDetailDto();
            detailDto.setContractId(contractVo.getId());
            List<PurchaseOrderDetailVo> details = detailService.listBy(detailDto);
            if (!CollectionUtils.isEmpty(details)) {
                contractVo.setSupplierName(details.get(0).getSupplierName());
                contractVo.setProjectName(details.get(0).getProjectName());
                contractVo.setPaymentSituation(details.get(0).getPaymentSituation());
                BigDecimal totalAmount = new BigDecimal(0);
                for (PurchaseOrderDetailVo detailVo : details) {
                    totalAmount = totalAmount.add(detailVo.getMaterialTotalPrice());
                }
                contractVo.setContractAmount(totalAmount);
            }
        }
        return page.setRecords(contractVos);
    }

    @Override
    public List<PurchaseIndentVo> findGenIndent(Long orderId, Long supplierId) {
        List<PurchaseIndentVo> result = new ArrayList<>();
        if (null == orderId && null == supplierId) {
            result = genContract();
        }
        List<Long> needMergeIndnetIds = this.baseMapper.findNeedMergeIndent(orderId, supplierId);
        if (CollectionUtils.isEmpty(needMergeIndnetIds)) {
            return result;
        }
        PurchaseOrder purchaseOrder = orderMapper.selectById(orderId);
        PurchaseSupplier supplier = supplierService.getById(supplierId);
        for (Long indentId : needMergeIndnetIds) {
            PurchaseIndent purchaseIndent = indentService.getById(indentId);
            PurchaseIndentVo indentVo = new PurchaseIndentVo(purchaseIndent, purchaseOrder, supplier);
            result.add(indentVo);
        }
        return result;
    }

    @Override
    public List<PurchaseIndentVo> genContract() {
        List<PurchaseIndentVo> result = new ArrayList<>();
        //查询空的 采购订单
        List<PurchaseIndent> purchaseIndents = indentService.listValidIndentWithoutContract();
        if (CollectionUtils.isEmpty(purchaseIndents)) {
            return result;
        }
        Set<Long> needProcesseIndents = purchaseIndents.stream().map(PurchaseIndent::getId).collect(Collectors.toSet());

        List<PurchaseOrderDetail> details = this.baseMapper.findMergeIndentInfo();
        if (!CollectionUtils.isEmpty(details)) {
            for (PurchaseOrderDetail detail : details) {
                PurchaseOrder purchaseOrder = orderMapper.selectById(detail.getOrderId());
                PurchaseSupplier supplier = supplierService.getById(detail.getSupplierId());
                List<PurchaseOrderDetail> temp = detailService.list(new QueryWrapper<>(detail));
                Set<Long> canMergeIndents = temp.stream().map(PurchaseOrderDetail::getIndentId).collect(Collectors.toSet());
                //求交集
                canMergeIndents.retainAll(needProcesseIndents);
                if (!CollectionUtils.isEmpty(canMergeIndents)) {
                    for (Long indentId : canMergeIndents) {
                        PurchaseIndent purchaseIndent = indentService.getById(indentId);
                        PurchaseIndentVo indentVo = new PurchaseIndentVo(purchaseIndent, purchaseOrder, supplier);
                        result.add(indentVo);
                    }
                    needProcesseIndents.removeAll(canMergeIndents);
                }
            }
        }

        for (Long identId : needProcesseIndents) {
            PurchaseIndent indent = indentService.getById(identId);
            PurchaseContract contract = new PurchaseContract();
            contract.setContractCode(indent.getIndentCode());
            this.save(contract);
            indent.setContractId(contract.getId());
            indentService.updateById(indent);
        }
        return result;

    }

    @Override
    public void deleteContracts(List<Long> ids) {
        for (Long contractId : ids) {
            indentService.emptyContractId(contractId);
            this.removeById(contractId);
            paymentService.deleteByContractId(contractId);
        }
    }

    @Override
    public void mergeIndent(String contractCode, String comment, List<Long> indentIds) {

        List<PurchaseIndent> indents = indentService.listByIds(indentIds);
        if (CollectionUtils.isEmpty(indentIds)) {
            throw new AppException("采购订单id不能为空");
        } else if (indents.size() != indentIds.size()) {
            throw new AppException("数据库缺少采购订单");
        }
        if (indents.stream().filter(e -> e.getContractId() != null).count() > 0) {
            throw new AppException("采购订单已有绑定合同");
        }
        List<PurchaseOrderDetail> allDetails = new ArrayList<>();
        for (Long indentId : indentIds) {
            PurchaseOrderDetail detailFilter = new PurchaseOrderDetail();
            detailFilter.setIndentId(indentId);
            List<PurchaseOrderDetail> details = detailService.list(new QueryWrapper<>(detailFilter));
            allDetails.addAll(details);
        }
        if (allDetails.stream().map(PurchaseOrderDetail::getSupplierId).distinct().count() > 1) {
            throw new AppException("合并的订单属于不同的供应商");
        }
        PurchaseContract contract = new PurchaseContract();
        contract.setContractCode(contractCode);
        contract.setContractComment(comment);
        this.save(contract);
        //更新id

        for (PurchaseIndent indent : indents) {
            indent.setContractId(contract.getId());
            indentService.updateById(indent);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateContract(PurchaseContractDto contractDto) {
        if (!CollectionUtils.isEmpty(contractDto.getPayments())) {
            for (PurchasePaymentDto paymentDto : contractDto.getPayments()) {
                if (null == paymentDto.getProportion() || null == paymentDto.getPayAmount()) {
                    throw new AppException("付款比例或金额不能为空");
                }
            }
        }
        PurchaseContract contract = BeanUtil.copyProperties(contractDto, PurchaseContract.class);
        this.updateById(contract);
        paymentService.deleteByContractId(contractDto.getId());
        List<PurchasePaymentDto> paymentDtos = contractDto.getPayments();
        if (!CollectionUtils.isEmpty(paymentDtos)) {
            for (PurchasePaymentDto paymentDto : paymentDtos) {
                PurchasePayment payment = BeanUtil.copyProperties(paymentDto, PurchasePayment.class);
                payment.setContractId(contractDto.getId());
                paymentService.save(payment);
            }
        }
    }

    @Override
    public PurchaseContractDetailVo getContractDetail(Long contractId) {
        PurchaseContract contract = this.getById(contractId);
        if (null == contract) {
            throw new AppException("合同不存在：" + contractId);
        }
        PurchaseContractDetailVo detailVo = BeanUtil.copyProperties(contract, PurchaseContractDetailVo.class);
        PurchaseOrderDetailDto filterDto = new PurchaseOrderDetailDto();
        filterDto.setContractId(contractId);
        List<PurchaseOrderDetailVo> orderDetails = detailService.listBy(filterDto);
        List<PurchasePayment> payments = paymentService.listByContractId(contractId);
        detailVo.setPayments(payments);
        if (!CollectionUtils.isEmpty(orderDetails)) {
            detailVo.setOrderDetails(orderDetails);
            detailVo.setContractAmount(orderDetails.get(0).getContractSubAmount());
        }
        return detailVo;
    }

    @Override
    public void initAllPayAmount() {
        List<PurchasePayment> allPayments = paymentService.list();
        for (PurchasePayment payment : allPayments) {
            initPayAmount(payment);
        }
    }


    @Override
    public void initPayAmount(PurchasePayment payment) {
        if (null != payment && null == payment.getPayAmount()) {
            PurchaseOrderDetailDto filterDto = new PurchaseOrderDetailDto();
            filterDto.setContractId(payment.getContractId());
            List<PurchaseOrderDetailVo> orderDetails = detailService.listBy(filterDto);
            if (CollectionUtils.isEmpty(orderDetails)) {
                return;
            }
            BigDecimal contractSubAmount = orderDetails.get(0).getContractSubAmount();
            if (null != contractSubAmount) {
                payment.setPayAmount(contractSubAmount.multiply(new BigDecimal(payment.getProportion().floatValue() / 100.0)).setScale(2, RoundingMode.HALF_UP));
                payment.setEditAmount(false);
                this.paymentService.updateById(payment);
            }
        }
    }

    @Override
    public PurchaseContract validPurchaseContract(PurchaseContract contract) {
        if (StringUtils.isEmpty(contract.getContractCode())) {
            throw new AppException("");
        }
        PurchaseContract filter = new PurchaseContract();
        filter.setContractCode(contract.getContractCode());
        PurchaseContract dbContract = this.getOne(new QueryWrapper<>(filter));
        if (null == dbContract) {
            this.save(contract);
            return contract;
        }
        return dbContract;

    }

    @Override
    public File exportPayment(Long contractId, Long paymentId, Boolean exWithInvoice) {
        //查询所有相关内容
        PurchaseContract contract = this.getById(contractId);
        if (null == contract) {
            throw new AppException("合同id不存在");
        }
        PurchaseOrderDetailDto filterDto = new PurchaseOrderDetailDto();
        if (exWithInvoice) {
            if (StringUtils.isEmpty(contract.getInvoice())) {
                throw new BaseException("发票号不存在");
            }
            filterDto.setInvoice(contract.getInvoice());
        } else {
            filterDto.setContractId(contractId);
        }
        List<PurchaseOrderDetailVo> orderDetails = detailService.listBy(filterDto);
        if (CollectionUtils.isEmpty(orderDetails)) {
            throw new AppException("");
        }
        //获取supplier 信息
        List<Long> supplierIdList = orderDetails.stream().map(PurchaseOrderDetailVo::getSupplierId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(supplierIdList) || supplierIdList.size() > 1) {
            throw new AppException("改合同包含0个或多个供应商，不支持导出");
        }
        Long supplierId = supplierIdList.get(0);
        PurchaseSupplier supplier = this.supplierService.getById(supplierId);

        //获取 project 信息
        Set<String> projectNames = orderDetails.stream().filter(e -> null != e.getProjectName()).map(e -> e.getProjectName().trim()).collect(Collectors.toSet());
        String projectName = CollUtil.join(projectNames, ",");
        //获取 审批单编号
        Set<String> orderCodes = orderDetails.stream().map(PurchaseOrderDetailVo::getOrderCode).collect(Collectors.toSet());
        String orderCode = CollUtil.join(orderCodes, ",");
        //获取payment信息
        PurchasePayment payment = null;
        if (exWithInvoice) {
            // do nothing
        } else if (null == paymentId) {
            List<PurchasePayment> payments = paymentService.listByContractId(contractId);
            if (!CollectionUtils.isEmpty(payments)) {
                payment = payments.get(0);
            }
        } else {
            payment = this.paymentService.getById(paymentId);
        }

        // 组装导出参数
        PaymentApprovalInfo approvalInfo = new PaymentApprovalInfo();
        DateTimeFormatter dfcn = DateTimeFormatter.ofPattern("yyyy年M月d日");
        approvalInfo.setCurDate(dfcn.format(LocalDate.now()));
        approvalInfo.setOrderCode(orderCode);
        approvalInfo.setSupplierName(supplier.getSupplierName());
        approvalInfo.setContactPerson(supplier.getContactPerson());
        approvalInfo.setContactPhone(supplier.getContactPhone());
        approvalInfo.setBankAccount(supplier.getBankAccount());
        approvalInfo.setBankName(supplier.getBankName());
        approvalInfo.setContractCode(contract.getContractCode());
        approvalInfo.setAogSituation(contract.getAogSituation());
        BigDecimal totalAmount = new BigDecimal(0);
        StringBuilder sb = new StringBuilder("");
        for (PurchaseOrderDetailVo detailVo : orderDetails) {
            totalAmount = totalAmount.add(detailVo.getMaterialTotalPrice());
            sb.append(detailVo.getMaterialName() + "-" + detailVo.getMaterialSpecification() + "-" + detailVo.getMaterialNum() + detailVo.getUnit() + ";   ");
        }
        approvalInfo.setEquipments(sb.toString());
        approvalInfo.setTotalAmount(totalAmount);
        if (null == payment) {
            approvalInfo.setProportion(new BigDecimal(100));
            approvalInfo.setPaymentDate("");
            approvalInfo.setPayAmount(totalAmount);
        } else {
            approvalInfo.setProportion(payment.getProportion());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日");
            approvalInfo.setPaymentDate(null == payment.getPaymentDate() ? "" : sdf.format(payment.getPaymentDate()));
//            totalAmount.multiply(new BigDecimal(approvalInfo.getProportion() / 100.0)).setScale(2, RoundingMode.HALF_UP)
            approvalInfo.setPayAmount(payment.getPayAmount());
        }
        approvalInfo.setPayAmountInWords(Amount2RMBUtil.convert(String.format("%.2f", approvalInfo.getPayAmount())));
        approvalInfo.setInvoice(contract.getInvoice());
        approvalInfo.setProjectName(projectName);


        File exportFile = null;
        try {
            ClassPathResource templateFileResource = new ClassPathResource("templates/payment-template.xls");
            exportFile = PathUtil.getTempFile(approvalInfo.getContractCode() + "_.xls");
            FileUtils.copyInputStreamToFile(templateFileResource.getInputStream(), exportFile);
            PurchaseUtils.exportPaymentApproval(approvalInfo, exportFile);
        } catch (Exception e) {
            throw new AppException("文件读取失败" + e.getMessage());
        }
        return exportFile;
    }

    @Override
    public List<PurchasePayment> queryPayments(Long contractId) {
        return paymentService.listByContractId(contractId);
    }


    @Override
    public File exportIndent(Long contractId, Long indentId) {
        //查询所有相关内容
        PurchaseContract contract = this.getById(contractId);
        if (null == contract) {
            throw new AppException("合同id不存在");
        }

        PurchaseOrderDetailDto filterDto = new PurchaseOrderDetailDto();
        filterDto.setContractId(contractId);
        filterDto.setIndentId(indentId);
        List<PurchaseOrderDetailVo> orderDetails = detailService.listBy(filterDto);
        if (CollectionUtils.isEmpty(orderDetails)) {
            throw new AppException("未找到订单详情");
        }
        //获取supplier 信息
        List<Long> supplierIdList = orderDetails.stream().map(PurchaseOrderDetailVo::getSupplierId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(supplierIdList) || supplierIdList.size() > 1) {
            throw new AppException("改合同包含0个或多个供应商，不支持导出");
        }
        Long supplierId = supplierIdList.get(0);
        PurchaseSupplier supplier = this.supplierService.getById(supplierId);

        //获取 project 信息
        String projectName = orderDetails.get(0).getProjectName();

        String indentCode = orderDetails.get(0).getIndentCode();
        List<PurchaseMaterialBo> materialBos = new ArrayList<>(orderDetails.size());
        for (PurchaseOrderDetailVo detailVo : orderDetails) {
            materialBos.add(BeanUtil.copyProperties(detailVo, PurchaseMaterialBo.class));
        }

        File exportFile = null;
        try {
            ClassPathResource templateFileResource = new ClassPathResource("templates/indent-template.xls");
            exportFile = PathUtil.getTempFile(indentCode + "_.xls");
            FileUtils.copyInputStreamToFile(templateFileResource.getInputStream(), exportFile);
            PurchaseUtils.exportIndent(indentCode, supplier.getSupplierName(), projectName, materialBos, exportFile);
        } catch (Exception e) {
            throw new AppException("文件读取失败" + e.getMessage());
        }
        return exportFile;
    }

    @Override
    public List<PurchaseIndentSimpleVo> queryIndents(Long contractId) {
        PurchaseIndent filter = new PurchaseIndent();
        filter.setContractId(contractId);
        List<PurchaseIndent> indents = this.indentService.list(new QueryWrapper<>(filter));
        PurchaseOrderDetailDto filterDto = new PurchaseOrderDetailDto();
        filterDto.setContractId(contractId);
        List<PurchaseOrderDetailVo> orderDetails = detailService.listBy(filterDto);

        List<PurchaseIndentSimpleVo> res = new ArrayList<>(indents.size());
        for (PurchaseIndent indent : indents) {
            PurchaseIndentSimpleVo indentSimpleVo = BeanUtil.copyProperties(indent, PurchaseIndentSimpleVo.class);
            BigDecimal totalPrice = new BigDecimal(0);
            List<PurchaseOrderDetailVo> temp = orderDetails.stream().filter(e -> e.getIndentId().equals(indentSimpleVo.getId())).collect(Collectors.toList());
            for (PurchaseOrderDetailVo detailVo : temp) {
                totalPrice = totalPrice.add(detailVo.getMaterialTotalPrice());
            }
            indentSimpleVo.setTotalPrice(totalPrice);
            res.add(indentSimpleVo);
        }
        return res;
    }
}
